package com.andon.lcz.h264rtmp.pusher;

import android.app.Activity;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;

import com.andon.lcz.h264rtmp.params.VideoParam;

import java.util.Iterator;
import java.util.List;

public class VideoPusher extends Pusher implements SurfaceHolder.Callback, Camera.PreviewCallback {

    private static final String TAG = VideoPusher.class.getSimpleName();

    private SurfaceHolder holder;

    private VideoParam videoParam;

    private Camera camera;

    // 预览缓冲区，镜头方向转换后缓冲区
    private byte[] buffer, rawBuffer;

    private Activity activity;

    // 当前手机的方向
    private int orientation;

    public VideoPusher(Activity activity, PusherNative pusherNative, VideoParam videoParam, SurfaceHolder holder) {
        super(pusherNative);
        this.videoParam = videoParam;
        this.holder = holder;
        this.holder.addCallback(this);
        this.activity = activity;
    }

    @Override
    public void start() {
        super.start();
        startPreview();
    }

    @Override
    public void stop() {
        super.stop();
        stopPreview();
    }

    @Override
    public void release() {

    }

    // 切换摄像头
    public void switchCamera() {
        stopPreview();
        if (videoParam.getCameraId() == Camera.CameraInfo.CAMERA_FACING_BACK) {
            videoParam.setCameraId(Camera.CameraInfo.CAMERA_FACING_FRONT);
        } else {
            videoParam.setCameraId(Camera.CameraInfo.CAMERA_FACING_BACK);
        }
        startPreview();
    }

    // 开始预览
    private void startPreview() {
        try {
            camera = Camera.open(videoParam.getCameraId());
            Camera.Parameters parameter = camera.getParameters();
            parameter.setPreviewFormat(ImageFormat.NV21);
            setPreviewSize(parameter);
            camera.setParameters(parameter);
            setDisplayOrientation();
            int bitsPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.NV21);
            int bufferSize = videoParam.getWidth() * videoParam.getHeight() * bitsPerPixel / 8;
            buffer = new byte[bufferSize];
            rawBuffer = new byte[bufferSize];
            camera.addCallbackBuffer(buffer);
            camera.setPreviewCallbackWithBuffer(this);
            camera.setPreviewDisplay(holder);
            camera.startPreview();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 设置显示方向
    private void setDisplayOrientation() {
        Camera.CameraInfo info =
                new android.hardware.Camera.CameraInfo();
        Camera.getCameraInfo(videoParam.getCameraId(), info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        switch (rotation) {
            case Surface.ROTATION_0:
                orientation = 0;
                break;
            case Surface.ROTATION_90:
                orientation = 90;
                break;
            case Surface.ROTATION_180:
                orientation = 180;
                break;
            case Surface.ROTATION_270:
                orientation = 270;
                break;
        }
        if (orientation == 0 || orientation == 180) {
            pusherNative.setVideoOptions(videoParam.getHeight(), videoParam.getWidth(), videoParam.getBitrate(), videoParam.getFps());
        } else {
            pusherNative.setVideoOptions(videoParam.getWidth(), videoParam.getHeight(), videoParam.getBitrate(), videoParam.getFps());
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + orientation) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - orientation + 360) % 360;
        }
        camera.setDisplayOrientation(result);
    }

    // 设置摄像头的预览大小
    private void setPreviewSize(Camera.Parameters p) {
        List<Camera.Size> supportedSizes = p.getSupportedPreviewSizes();
        Camera.Size size = supportedSizes.get(0);
        int diff = Math.abs(size.width * size.height - videoParam.getWidth() * videoParam.getHeight());
        Iterator<Camera.Size> it = supportedSizes.iterator();
        it.next();
        while (it.hasNext()) {
            Camera.Size next = it.next();
            int n = Math.abs(next.width * next.height - videoParam.getWidth() * videoParam.getHeight());
            if (diff > n) {
                diff = n;
                size = next;
            }
        }
        videoParam.setWidth(size.width);
        videoParam.setHeight(size.height);
        p.setPreviewSize(size.width, size.height);
    }

    // 停止预览
    private void stopPreview() {
        if (camera != null) {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        if (isPushing) {
            stopPreview();
            startPreview();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        stopPreview();
    }

    /**
     * 相机预览的回调，只会回调一次，需要递归调用
     * bytes == buffer
     */
    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        Log.i(TAG, "onPreviewFrame called");
        if (isPushing) {
            rotateNV21Data2Raw();
            pusherNative.pushVideo(rawBuffer);
        }
        camera.addCallbackBuffer(bytes);
    }

    // 旋转摄像头的NV21数据
    private void rotateNV21Data2Raw() {
        int w = videoParam.getWidth(), h = videoParam.getHeight(), y_size = w * h, k = 0;
        switch (orientation) {
            case 0: {
                if (videoParam.getCameraId() == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    // 顺时针旋转90度
                    // y
                    for (int i = 0; i < w; i++) {
                        for (int j = h - 1; j >= 0; j--) {
                            rawBuffer[k++] = buffer[j * w + i];
                        }
                    }
                    // u/v
                    for (int i = 0; i < w; i += 2) {
                        for (int j = h / 2 - 1; j >= 0; j--) {
                            // v
                            rawBuffer[k++] = buffer[y_size + w * j + i];
                            // u
                            rawBuffer[k++] = buffer[y_size + w * j + i + 1];
                        }
                    }
                } else {
                    // 逆时针旋转90度
                    // y
                    for (int i = w - 1; i >= 0; i--) {
                        for (int j = 0; j < h; j++) {
                            rawBuffer[k++] = buffer[j * w + i];
                        }
                    }
                    // u/v
                    for (int i = w - 2; i >= 0; i -= 2) {
                        for (int j = 0; j < h / 2; j++) {
                            // v
                            rawBuffer[k++] = buffer[y_size + w * j + i];
                            // u
                            rawBuffer[k++] = buffer[y_size + w * j + i + 1];
                        }
                    }
                }
            }
            break;
            case 90: {
                // 手机逆时针旋转90度
                rawBuffer = buffer;
            }
            break;
            case 270: {
                // 手机顺时针旋转90度
                // y
                for (int i = y_size - 1; i >= 0; i--) {
                    rawBuffer[k++] = buffer[i];
                }
                // u/v
                for (int i = y_size * 3 / 2 - 2; i >= y_size; i -= 2) {
                    // v
                    rawBuffer[k++] = buffer[i];
                    // u
                    rawBuffer[k++] = buffer[i + 1];
                }
            }
            break;
        }
    }
}
